/*
 * Copyright (C) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

extern crate alloc;

use crate::Vec;
use core::convert::TryFrom;

use crate::common::constants::*;
use crate::common::types::*;
use crate::entry::user_auth_ffi::*;
use crate::log_e;
use crate::traits::event_manager::*;

#[macro_export]
macro_rules! impl_command_handler {
    (
        $handler_name:ident,
        $input_ffi_ty:ty,
        $input_rs_ty:ty,
        $output_ffi_ty:ty,
        $executor_ty:ty
    ) => {
        pub struct $handler_name {
            command_id: CommandId,
            access_policy: AccessPolicy,
            executor: $executor_ty,
        }

        impl $handler_name {
            pub fn new(
                command_id: CommandId,
                access_policy: AccessPolicy,
                executor: $executor_ty,
            ) -> Self {
                $handler_name {
                    command_id,
                    access_policy,
                    executor,
                }
            }
        }

        impl CommandHandler for $handler_name {
            fn command_id(&self) -> &CommandId {
                &self.command_id
            }

            fn access_policy(&self) -> &AccessPolicy {
                &self.access_policy
            }

            fn handle(&self, input: &[u8], output: &mut [u8]) -> Result<(), ErrorCode> {
                if input.len() != core::mem::size_of::<$input_ffi_ty>() {
                    log_e!(
                        "{} input size mismatch: {} != {}",
                        stringify!($handler_name),
                        input.len(),
                        core::mem::size_of::<$input_ffi_ty>()
                    );
                    return Err(ErrorCode::BadParam);
                }

                if output.len() != core::mem::size_of::<$output_ffi_ty>() {
                    log_e!(
                        "{} output size mismatch: {} != {}",
                        stringify!($handler_name),
                        output.len(),
                        core::mem::size_of::<$output_ffi_ty>()
                    );
                    return Err(ErrorCode::BadParam);
                }

                let input_ffi = unsafe { *(input.as_ptr() as *const $input_ffi_ty) };
                let input_rs = match <$input_rs_ty>::try_from(input_ffi) {
                    Ok(input) => input,
                    Err(e) => {
                        log_e!(
                            "{} convert input fail, error: {:?}",
                            stringify!($handler_name),
                            e
                        );
                        return Err(ErrorCode::GeneralError);
                    }
                };

                let output_rs = match self.executor.execute(input_rs) {
                    Ok(result) => result,
                    Err(e) => {
                        log_e!("{} handle fail, error: {:?}", stringify!($handler_name), e);
                        return Err(e);
                    }
                };

                let output_ffi = match <$output_ffi_ty>::try_from(output_rs) {
                    Ok(ffi) => ffi,
                    Err(e) => {
                        log_e!(
                            "{} convert output fail, error: {:?}",
                            stringify!($handler_name),
                            e
                        );
                        return Err(ErrorCode::GeneralError);
                    }
                };

                unsafe {
                    core::ptr::write(output.as_mut_ptr() as *mut $output_ffi_ty, output_ffi);
                }
                log_i!("{} success", stringify!($handler_name));
                Ok(())
            }
        }
    };
}

// Common
pub fn vec_from_array_with_len<T: Clone>(array: &[T], len: u32) -> Result<Vec<T>, ErrorCode> {
    if len as usize > array.len() {
        log_e!(
            "Invalid length: max {}, actual {}",
            len as usize,
            array.len()
        );
        return Err(ErrorCode::BadParam);
    }
    Ok(array[..len as usize].to_vec())
}

pub fn _array_from_vec<T: Clone + core::marker::Copy, const N: usize>(
    vec: Vec<T>,
) -> core::result::Result<([T; N], u32), ErrorCode> {
    if vec.len() > N {
        log_e!("Invalid length: max {}, actual {}", N, vec.len());
        return Err(ErrorCode::BadParam);
    }

    let mut array = [vec[0]; N];
    for (i, item) in vec.iter().enumerate() {
        array[i] = *item;
    }
    Ok((array, vec.len() as u32))
}

pub fn array_from_vec_default<TIn, TOut, const N: usize>(
    vec: Vec<TIn>,
) -> core::result::Result<([TOut; N], u32), ErrorCode> 
where
    TOut: Default + Copy,
    TIn: TryInto<TOut, Error = ErrorCode>,
{
    if vec.len() > N {
        log_e!("Invalid length: max {}, actual {}", N, vec.len());
        return Err(ErrorCode::BadParam);
    }

    let len = vec.len() as u32;
    let mut array = [TOut::default(); N];
    for (i, item) in vec.into_iter().enumerate() {
        array[i] = item.try_into()?;
    }
    Ok((array, len))
}

// MessageArrayFfi
impl TryFrom<MessageArrayFfi> for Vec<u8> {
    type Error = ErrorCode;

    fn try_from(value: MessageArrayFfi) -> core::result::Result<Self, ErrorCode> {
        Ok(vec_from_array_with_len(&value.data, value.len)?)
    }
}

impl TryFrom<Vec<u8>> for MessageArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Vec<u8>) -> core::result::Result<Self, ErrorCode> {
        let (data, len) = _array_from_vec::<u8, MAX_MSG_LEN_FFI>(value)?;
        Ok(MessageArrayFfi { data, len })
    }
}

impl TryFrom<Option<RootSecret>> for MessageArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Option<RootSecret>) -> core::result::Result<Self, ErrorCode> {
        if let Some(secret) = value {
            if MAX_MSG_LEN_FFI < ROOT_SECRET_LEN {
                log_e!("root secret length {} exceeds max {}", ROOT_SECRET_LEN, MAX_MSG_LEN_FFI);
                return Err(ErrorCode::BadParam);
            }
            let mut output = MessageArrayFfi::default();
            output.data[..ROOT_SECRET_LEN].copy_from_slice(&secret);
            output.len = ROOT_SECRET_LEN_FFI as u32;
            Ok(output)
        } else {
            Ok(MessageArrayFfi::default())
        }
    }
}

// TemplateIdArrayFfi
impl TryFrom<TemplateIdArrayFfi> for Vec<TemplateId> {
    type Error = ErrorCode;

    fn try_from(value: TemplateIdArrayFfi) -> core::result::Result<Self, ErrorCode> {
        let template_ids: Vec<u64> = vec_from_array_with_len(&value.data, value.len)?;
        Ok(template_ids.into_iter().map(TemplateId).collect())
    }
}

impl TryFrom<Vec<TemplateId>> for TemplateIdArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Vec<TemplateId>) -> core::result::Result<Self, ErrorCode> {
        let template_ids: Vec<u64> = value.into_iter().map(|t| t.0).collect();
        let (data, len) = _array_from_vec::<u64, MAX_TEMPLATE_ID_NUM_FFI>(template_ids)?;
        Ok(TemplateIdArrayFfi { data, len })
    }
}

// UserIdArrayFfi
impl TryFrom<UserIdArrayFfi> for Vec<i32> {
    type Error = ErrorCode;

    fn try_from(value: UserIdArrayFfi) -> core::result::Result<Self, ErrorCode> {
        vec_from_array_with_len(&value.data, value.len)
    }
}

impl TryFrom<Vec<i32>> for UserIdArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Vec<i32>) -> core::result::Result<Self, ErrorCode> {
        let (data, len) = _array_from_vec::<i32, MAX_USER_NUM_FFI>(value)?;
        Ok(UserIdArrayFfi { data, len })
    }
}

// CredentialInfo
#[derive(Clone, Default)]
pub struct CredentialInfo {
    pub credential_id: CredentialId,
    pub executor_index: u64,
    pub template_id: TemplateId,
    pub auth_type: AuthType,
    pub executor_matcher: u32,
    pub executor_sensor_hint: u32,
    pub auth_sub_type: i32,
    pub is_abandoned: bool,
    pub validity_period: i64,
}

impl TryFrom<CredentialInfo> for CredentialInfoFfi {
    type Error = ErrorCode;

    fn try_from(value: CredentialInfo) -> core::result::Result<Self, ErrorCode> {
        Ok(CredentialInfoFfi {
            credential_id: value.credential_id.0,
            executor_index: value.executor_index,
            template_id: value.template_id.0,
            auth_type: value.auth_type as i32,
            executor_matcher: value.executor_matcher,
            executor_sensor_hint: value.executor_sensor_hint,
            auth_sub_type: value.auth_sub_type,
            is_abandoned: if value.is_abandoned { 1 } else { 0 },
            validity_period: value.validity_period,
        })
    }
}

impl TryFrom<Vec<CredentialInfo>> for CredentialArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Vec<CredentialInfo>) -> core::result::Result<Self, ErrorCode> {
        if value.len() > MAX_CREDENTIAL_NUM_FFI {
            log_e!(
                "CredentialInfo vector length {} exceeds max {}",
                value.len(),
                MAX_CREDENTIAL_NUM_FFI
            );
            return Err(ErrorCode::BadParam);
        }

        let value_len = value.len();
        let mut data = [CredentialInfoFfi::default(); MAX_CREDENTIAL_NUM_FFI];
        for (i, item) in value.into_iter().enumerate() {
            data[i] = item.try_into()?;
        }

        Ok(CredentialArrayFfi {
            data,
            len: value_len as u32,
        })
    }
}

// CommonOutput
#[derive(Clone, Default)]
pub struct CommonOutput {
    pub result: i32,
    pub has_fatal_error: bool,
    pub events: Vec<Event>,
}

impl TryFrom<CommonOutput> for CommonOutputFfi {
    type Error = ErrorCode;

    fn try_from(value: CommonOutput) -> core::result::Result<Self, ErrorCode> {
        Ok(CommonOutputFfi {
            result: value.result,
            has_fatal_error: value.has_fatal_error,
            events: value.events.try_into()?,
        })
    }
}

impl TryFrom<Event> for EventFfi {
    type Error = ErrorCode;

    fn try_from(value: Event) -> core::result::Result<Self, ErrorCode> {
        Ok(EventFfi {
            time: value.time,
            file_name: value.file_name.try_into()?,
            line_number: value.line_number,
            event_type: value.event_type as i32,
            event_info: value.event_info.try_into()?,
        })
    }
}

impl TryFrom<Vec<Event>> for EventArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Vec<Event>) -> core::result::Result<Self, ErrorCode> {
        let mut data = [EventFfi::default(); MAX_EVENT_NUM_FFI];
        for (i, item) in value.iter().enumerate() {
            data[i] = item.clone().try_into()?;
        }

        Ok(EventArrayFfi {
            data,
            len: value.len() as u32,
        })
    }
}

// AuthToken
impl TryFrom<AuthTokenArrayFfi> for Vec<u8> {
    type Error = ErrorCode;

    fn try_from(value: AuthTokenArrayFfi) -> core::result::Result<Self, ErrorCode> {
        Ok(vec_from_array_with_len(&value.data, value.len)?)
    }
}

impl TryFrom<Vec<u8>> for AuthTokenArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Vec<u8>) -> core::result::Result<Self, ErrorCode> {
        let (data, len) = _array_from_vec::<u8, MAX_AUTH_TOKEN_LEN_FFI>(value)?;
        Ok(AuthTokenArrayFfi { data, len })
    }
}

// ExecutorIndexArray
impl TryFrom<Vec<u64>> for ExecutorIndexArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Vec<u64>) -> core::result::Result<Self, ErrorCode> {
        let (data, len) = _array_from_vec::<u64, MAX_EXECUTOR_NUM_FFI>(value)?;
        Ok(ExecutorIndexArrayFfi { data, len })
    }
}

// ScheduleInfo
#[derive(Debug, Clone, Default)]
pub struct ScheduleInfo {
    pub schedule_id: u64,
    pub template_ids: Vec<TemplateId>,
    pub auth_type: AuthType,
    pub executor_matcher: u32,
    pub schedule_mode: ScheduleMode,
    pub executor_indexes: Vec<u64>,
    pub executor_messages: Vec<Vec<u8>>,
}

impl TryFrom<ScheduleInfo> for ScheduleInfoFfi {
    type Error = ErrorCode;

    fn try_from(value: ScheduleInfo) -> core::result::Result<Self, ErrorCode> {
        let mut executor_messages = [MessageArrayFfi::default(); MAX_EXECUTOR_NUM_FFI];
        for (i, msg) in value
            .executor_messages
            .iter()
            .enumerate()
            .take(MAX_EXECUTOR_NUM_FFI)
        {
            executor_messages[i] = msg.clone().try_into()?;
        }

        Ok(ScheduleInfoFfi {
            schedule_id: value.schedule_id,
            template_ids: value.template_ids.try_into()?,
            auth_type: value.auth_type as i32,
            executor_matcher: value.executor_matcher,
            schedule_mode: value.schedule_mode as i32,
            executor_indexes: value.executor_indexes.try_into()?,
            executor_messages,
            executor_message_count: value.executor_messages.len() as u32,
        })
    }
}

impl TryFrom<Vec<ScheduleInfo>> for ScheduleInfoArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Vec<ScheduleInfo>) -> core::result::Result<Self, ErrorCode> {
        if value.len() > MAX_SCHEDULE_NUM_FFI {
            log_e!(
                "ScheduleInfo vector length {} exceeds max {}",
                value.len(),
                MAX_SCHEDULE_NUM_FFI
            );
            return Err(ErrorCode::BadParam);
        }

        let value_len = value.len();
        let mut data = [ScheduleInfoFfi::default(); MAX_SCHEDULE_NUM_FFI];
        for (i, item) in value.into_iter().enumerate() {
            data[i] = item.try_into()?;
        }

        Ok(ScheduleInfoArrayFfi {
            data,
            len: value_len as u32,
        })
    }
}

// EnrolledINfo
#[derive(Clone, Default)]
pub struct EnrolledInfo {
    pub enrolled_id: u64,
    pub auth_type: AuthType,
}

impl TryFrom<EnrolledInfo> for EnrolledInfoFfi {
    type Error = ErrorCode;

    fn try_from(value: EnrolledInfo) -> core::result::Result<Self, ErrorCode> {
        Ok(EnrolledInfoFfi {
            enrolled_id: value.enrolled_id,
            auth_type: value.auth_type as i32,
        })
    }
}

impl TryFrom<Vec<EnrolledInfo>> for EnrolledInfoArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Vec<EnrolledInfo>) -> core::result::Result<Self, ErrorCode> {
        if value.len() > MAX_CREDENTIAL_NUM_FFI {
            log_e!(
                "EnrolledInfo vector length {} exceeds max {}",
                value.len(),
                MAX_CREDENTIAL_NUM_FFI
            );
            return Err(ErrorCode::BadParam);
        }

        let mut data = [EnrolledInfoFfi::default(); MAX_CREDENTIAL_NUM_FFI];
        for (i, item) in value.iter().enumerate() {
            data[i] = item.clone().try_into()?;
        }

        Ok(EnrolledInfoArrayFfi {
            data,
            len: value.len() as u32,
        })
    }
}

// EnrolledState
pub type EnrolledState = EnrolledStateFfi;

// AuthResultInfo
#[derive(Clone, Default)]
pub struct ExecutorSendMsg {
    pub executor_index: u64,
    pub command_id: i32,
    pub msg: Vec<u8>,
}

impl TryFrom<ExecutorSendMsg> for ExecutorSendMsgFfi {
    type Error = ErrorCode;

    fn try_from(value: ExecutorSendMsg) -> core::result::Result<Self, ErrorCode> {
        Ok(ExecutorSendMsgFfi {
            executor_index: value.executor_index,
            command_id: value.command_id,
            msg: value.msg.try_into()?,
        })
    }
}

#[derive(Clone, Default)]
pub struct AuthResultInfo {
    pub result: i32,
    pub lockout_duration: i32,
    pub remain_attempts: i32,
    pub msgs: Vec<ExecutorSendMsg>,
    pub token: Vec<u8>,
    pub root_secret: Option<RootSecret>,
    pub user_id: i32,
    pub credential_id: CredentialId,
    pub pin_expired_info: i64,
    pub remote_auth_result_msg: Vec<u8>,
    pub re_enroll_flag: bool,
}

impl TryFrom<Vec<ExecutorSendMsg>> for ExecutorSendMsgArrayFfi {
    type Error = ErrorCode;

    fn try_from(value: Vec<ExecutorSendMsg>) -> core::result::Result<Self, ErrorCode> {
        if value.len() > MAX_EXECUTOR_NUM_FFI {
            log_e!(
                "ExecutorSendMsgArrayFfi length {} exceeds max {}",
                value.len(),
                MAX_EXECUTOR_NUM_FFI
            );
            return Err(ErrorCode::BadParam);
        }

        let mut data = [ExecutorSendMsgFfi::default(); MAX_EXECUTOR_NUM_FFI];
        for (i, msg) in value.iter().enumerate().take(MAX_EXECUTOR_NUM_FFI) {
            data[i] = msg.clone().try_into()?;
        }
        Ok(ExecutorSendMsgArrayFfi {
            data: data,
            len: value.len() as u32,
        })
    }
}

impl TryFrom<AuthResultInfo> for AuthResultInfoFfi {
    type Error = ErrorCode;

    fn try_from(value: AuthResultInfo) -> core::result::Result<Self, ErrorCode> {
        Ok(AuthResultInfoFfi {
            result: value.result,
            lockout_duration: value.lockout_duration,
            remain_attempts: value.remain_attempts,
            msgs: value.msgs.try_into()?,
            token: value.token.try_into()?,
            root_secret: value.root_secret.try_into()?,
            user_id: value.user_id,
            credential_id: value.credential_id.0,
            pin_expired_info: value.pin_expired_info,
            remote_auth_result_msg : value.remote_auth_result_msg.try_into()?,
            re_enroll_flag: value.re_enroll_flag,
        })
    }
}

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct AssociateId {
    pub context_id: u64,
    pub user_id: i32
}

impl AssociateId {
    pub fn init() -> Self{
        Self {
            context_id: 0,
            user_id: 0
        }
    }
}

#[repr(C)]
#[derive(Debug, Clone, PartialEq)]
pub struct ScheduleParam {
    pub auth_type: AuthType,
    pub schedule_mode: ScheduleMode,
    pub associate_id: AssociateId,
    pub template_ids: Vec<TemplateId>,
    pub collector_sensor_hint: u32,
    pub verifier_sensor_hint: u32,
    pub executor_matcher: u32,
    pub user_type: UserType,
    pub local_udid: Udid,
    pub collector_udid: Udid
}

impl ScheduleParam {
    pub fn new(
        auth_type: AuthType,
        schedule_mode: ScheduleMode,
        associate_id: AssociateId,
        template_ids: Vec<TemplateId>,
        collector_sensor_hint: u32,
        verifier_sensor_hint: u32,
        executor_matcher: u32,
        user_type: UserType,
        local_udid: Udid,
        collector_udid: Udid
    ) -> Self {
        Self {
            auth_type,
            schedule_mode,
            associate_id,
            template_ids,
            collector_sensor_hint,
            verifier_sensor_hint,
            executor_matcher,
            user_type,
            local_udid,
            collector_udid
        }
    }
}